/*
 file: hash.js
 dependsOn: core.js, class.js
 */

$.Hash = $.newClass(
{
  construct: function(object) 
  {
    this._object = $.isA(Hash) ? object.toObject() : $.clone(object);
  },

  each: function(iterator) 
  {
    var key, value, pair;
    
    for (key in this._object) {
      value = this._object[key]; 
      pair = [key, value];
      pair.key = key;
      pair.value = value;
      
      if(iterator(pair) == $.BREAK) 
        break;
    }
  },

  set: function(key, value) 
  {
    return this._object[key] = value;
  },

  get: function(key) 
  {
    // simulating poorly supported hasOwnProperty
    if (this._object[key] !== Object.prototype[key])
      return this._object[key];
  },

  remove: function(key) 
  {
    delete this._object[key];
  },

  toObject: function() 
  {
    return $.clone(this._object);
  },

  keys: function() 
  {
    return this.pluck('key');
  },

  values: function() 
  {
    return this.pluck('value');
  },

  index: function(value) 
  {
    var match = this.detect(function(pair) {
      return pair.value === value;
    });
    
    return match && match.key;
  },

  merge: function(object) 
  {
    return this.clone().update(object);
  },

  update: function(object) 
  {
    return new $.Hash(object).inject(this, 
      function(result, pair) {
        result.set(pair.key, pair.value);
        return result;
      });
  },

  toQueryString: function() 
  {
    return this.inject([], function(results, pair) {
      var key = encodeURIComponent(pair.key), values = pair.value;

      if (values && typeof values == 'object') {
        if (Object.isArray(values))
          return results.concat(values.map(toQueryPair.curry(key)));
      } 
      else 
        results.push(toQueryPair(key, values));
        
      return results;
    }).join('&');
  },

  inspect: function() 
  {
    return '#<Hash:{' + this.map(function(pair) {
      return pair.map($.inspect).join(': ');
    }).join(', ') + '}>';
  },

  toJSON: function() 
  {
    return $.toJSON(this._object);
  },

  clone: function() 
  {
    return new $.Hash(this);
  }
}).addMethods($.Enumerable); // Add the Enumerable mixin
